(***************************************************
Ant Movie Catalog importation script
www.antp.be/software/moviecatalog/
[Infos]
Authors=scorpion7552 (scripts originaux: Antoine Potten (MrCinéma) et Danone-Kid (Cinéfil))
Title=Monsieur Cinéma
Description=infos de MrCinéma - mode normal/batch: voir l'onglet Commentaires
Site=http://cinema.tiscali.fr
Language=FR
Version=5.2
Requires=3.5.0
Comments=mode batch: 2 modes possibles: d'après l'url mémorisée (MrCinéma) ou d'après le nom du film + réalisateur (résultats non garantis!)|N'oubliez pas de sauvegarder votre base actuelle avant de lancer le mode batch|Conseils: sélectionnez un nombre raisonnable de films et triez la liste des films par numéros|à la fin de chaque mise à jour, un fichier log est créé (informations et erreurs - attention ce fichier est recréé à chaque lancement de ce script)
License=This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version.
GetInfo=1
[Options]
Image=1|1|0=aucune image|1=image MrCinéma seule|2=image Cinéfil seule|3=toutes les images
Histoire=0|0|0=résumé (s'il existe, sinon histoire complète)|1=histoire complète
Anecdote=0|0|0=pas d'anecdote|1=anecdote à la suite de l'avis de la rédaction (Commentaires)
Générique=0|0|0=générique réduit|1=générique complet
FormatTitre=0|0|0=laisser les titres des films tels quels|1=tout en minuscules|2=tout en majuscules|3=1ère lettre en majuscule le reste en minuscules|4=toutes les 1ères lettres en majuscules
Mode=0|0|0=mode normal|1=mode batch (url)|2=mode batch (nom + réalisateur)
***************************************************)
// nécessite les modules suivants
// StringUtils1.pas, StringUtils7552.pas et MrCinemaCinefilCommon.pas
program MonsieurCinema;
uses
MrCinemaCinefilCommon;
const
MrCinemaUrl = 'http://cinema.tiscali.fr/';
MrCinemaUrlFilm = MrCinemaUrl + 'fichefilm.aspx';
{ recherche: films classés par titres (on peut aussi faire &filtre=annee)}
MrCinemaUrlLook = MrCinemaUrl + 'recherche.aspx?file=http&filtre=titre&keys=';
var
viewstate, idhistoire, idavis, idgenerique, idanecdote, annee: string;
ImportPicture: integer;
//------------------------------------------------------------------------------
// recherche du film
// MovieName = nom du film cherché (tel que saisi, cad non formaté)
//------------------------------------------------------------------------------
procedure AnalyzePageMrCinema;
var
Address, Page, Value, PageFilm, urlFilm: String;
pagenum, i: integer;
memo: TStringList;
begin
pagenum := 0; // compteur de pages
// init adresse 1ère recherche
Address := MrCinemaUrlLook+FormatMovieName2(MovieName);
repeat
PageNext := '';
PagePrev := '';
// traitement page courante
// attention aux positionnements: les textes sont au format UTF-8
pagenum := pagenum + 1;
FormatUTF8 := 1;
memoAdr := TStringList.Create; // init listes de mémo
memoTxt := TStringList.Create;
Page := GetPage(UrlEncode(Address));
if debug then
DumpPage(debugrep+'choixMrCinema'+IntToStr(pagenum)+'.txt', Page); // debug
Page := TextAfter(Page, 'Vous effectuez une recherche sur');
if Page = '' then
begin
LogMessage('MrCinéma: erreur lecture page de recherche '+IntToStr(pagenum));
memoAdr.Free;
memoTxt.Free;
exit;
end;
// c'est ici qu'il faudrait mémoriser PagePrev/PageNext
// pour l'instant il n'y en pas, mais c'est pas une raison pour ne pas le prévoir ...
if PagePrev <> '' then
begin
memoAdr.Add(PagePrev);
memoTxt.Add('<<< page précédente');
end;
// mémo des films de cette page (if any)
urlFilm := ' 0 then
begin
// mode batch : recherche du meilleur poids pour les films de cette page
LookBest(mrcinema_id);
if (bestpoids = maxcount) or (PageNext = '') or (pagenum > pagemax) then
// poids max ou pas de page next ou max pages lues: on arrete
begin
if bestpoids > 0 then // on a trouvé quelque chose
begin
if bestpoids < maxcount then // infos partielles
LogMessage('MrCinéma: '+looktxt+' retenu '+besttxt+' (poids='+IntToStr(bestpoids)+')');
AnalyzeMoviePageMrCinema(bestadr); // page film
end else
LogMessage('MrCinéma: pas de correspondance pour '+looktxt);
break; // on sort
end else
// sinon, on va chercher s'il y a mieux mieux dans pagenext
Address := PageNext;
end else
// mode normal
begin
Address := SelectMovie('Films (Monsieur Cinéma)');
if Address <> '' then
begin
if (Address <> PageNext) and (Address <> PagePrev) then
begin
AnalyzeMoviePageMrCinema(Address); // page film
break; // on sort
end;
end else
LogMessage('MrCinéma: aucun film sélectionné');
end;
until (Address = '');
memoAdr.Free;
memoTxt.Free;
end;
//------------------------------------------------------------------------------
// analyse de la page du film
//------------------------------------------------------------------------------
procedure AnalyzeMoviePageMrCinema(Address: string);
var
Fullpage, PageEssentiel, PageHistoire, PageAvis, PageGenerique, PageAnecdote: string;
Value, Value2, titreo, titret, realisateur, producteur, duree, acteurs: string;
memo: TStringList;
i: integer;
begin
// attention aux positionnements: les textes sont au format UTF-8
FormatUTF8 := 1;
annee := '';
Fullpage := GetPage(Address); // charge la 1ère page ("l'essentiel")
if debug then
DumpPage(debugrep+'filmMrCinema.txt', Fullpage); // debug
if Pos('L''essentiel', Fullpage) = 0 then
Begin
LogMessage('MrCinéma: erreur lecture page essentiel');
exit;
end;
filmok := True; // ça y est, c'est bon
SetField(fieldURL, Address);
GetSubParms(Fullpage); // récupère les identifiants des pages secondaires
// infos utiles de la page "essentiel"
PageEssentiel := TextBetween(Fullpage, '', '');
//********** générique
//*** les infos du générique sont plus ou moins valorisées
//*** quant à l'année, elle peut être vraiment n'importe où !!!
// si générique complet demandé
if (GetOption('Générique') = 1) and (idgenerique <> '') then
begin
PageGenerique := GetSubPage(Address, idgenerique, 'generique');
// titre Original/traduit
titret := TextBetween(PageGenerique, '', '');
titreo := TextBetween(PageGenerique, '', '');
// séparer les 2 tables
Value := TextBetween(PageGenerique, '
'); // infos générales
acteurs := TextBetween(RemainingText, ''); // rôles/acteurs
// acteurs
acteurs := FormatTable(acteurs, 'nocont'); // ne pas recoller les lignes
acteurs := StringReplace(acteurs, sepchar2, '-');
// infos générales
Value := FormatTable(Value, ''); // recoller les lignes
// réalisateur (et année)
realisateur := ExtractInfo(Value, 'réalis'); // réalisation, réalisateur, réalisé,...
ExtrAnnee(realisateur);
// producteur (parfois c'est "réalisé et produit par machin (année)" )
producteur := ExtractInfo(Value, 'produ'); // produit, production, ...
ExtrAnnee(producteur);
// durée
duree := ExtractInfo(Value, 'durée'); // durée
duree := FormatText(TextBefore(duree, 'minutes', ''));
end;
// si pas de générique complet ou champs non trouvés, on essaie dans la page 'essentiel'
// titre original
if titret = '' then
titret := TextBetween(PageEssentiel, '', '');
// titre traduit (et année)
Value := TextBetween(PageEssentiel, '', '');
ExtrAnnee(Value); // 5.1: l'année est maintenant ici
if titreo = '' then
titreo := Value;
// réalisateur
Value := TextAfter(PageEssentiel, '
');
if realisateur = '' then
realisateur := TextBetween(Value, 'de', '');
// année (anciennes fiches)
if annee = '' then
begin
annee := TextBetween(Value, '', 'avec');
annee := TextBetween(annee, '(', ')');
end;
// acteurs
if acteurs = '' then
begin
acteurs := TextBetween(Value, 'avec', '', '
'); // résumé
if (idhistoire <> '') and ((Value = '') or (GetOption('Histoire') = 1) or (Pos('>Lire la suite<', Value) > 0)) then
begin // 5.1 pas de résumé ou début de histoire complète ou histoire complète demandée
PageHistoire := GetSubPage(Address, idhistoire, 'histoire');
Value := TextBetween(PageHistoire, '', '
');
end;
SetField(fieldDescription, FormatText(Value));
//********** avis de la rédaction, note (peuvent être dans la page "essentiel") + anecdote
Value := '';
PageAvis := TextAfter(Fullpage, 'L''avis de la rédaction' );
if (PageAvis = '') and (idavis <> '') then // avis sur autre page
PageAvis := GetSubPage(Address, idavis, 'avis');
Value := FormatText(TextBetween(PageAvis, ''));
// Value = avis de la rédaction: garder pour compléter avec l'anecdote
Value2 := TextBetween(PageAvis, '
Aucun avis de la redaction.', PageAvis) > 0) and (Value2 = '0') then
Value2 := ''; // pas d'avis et img = 0redac.gif alors ignorer
if Value2 <> '' then
Value2 := IntToStr(StrToInt(Value2, 0) * 2); // note = 2 * x
SetField(fieldRating, Value2);
// on ajoute l'anecdote si demandé et existant
if (GetOption('Anecdote') = 1) and (idanecdote <> '') then
begin
PageAnecdote := GetSubPage(Address, idanecdote, 'anecdote');
Value2 := FormatText(TextBetween(PageAnecdote, '', '
'));
if Value2 <> '' then
begin
if Value <> '' then Value := Value + crlf + crlf;
Value := Value + 'Anecdote' + crlf + Value2;
end;
end;
SetField(fieldComments, Value);
//********** hors zone dynamique
// 5.2 changement de certains tags
Value2 := TextBetween(Fullpage, '');
// genre
Value := FormatText(TextBetween(Value2, 'Genre', ''));
SetField(fieldCategory, Value);
// durée (sauf si déjà fait)
if duree = '' then
begin // format hh:mm:ss à transformer en minutes
duree := FormatText(TextBetween(Value2, 'Durée', ''));
if duree <> '' then // format hh:mm:ss
duree := IntToStr(StrToInt(Left(duree, 2), 0) * 60 + StrToInt(Copy(duree, 4, 2), 0));
end;
SetField(fieldLength, duree); // on range maintenant
// pays
Value := FormatText(TextBetween(Value2, 'Pays ', ''));
if Value <> '' then
begin // pas toujours très cohérents les noms de pays...
Value := StringReplace(Value, '.', '');
Value := StringReplace(Value, ',', '');
Value := StringReplace(Value, '/', ' ');
Value := StringReplace(Value, '-' ,' ');
Value := CompactString(Value, '');
Value := TranslateText(Value, 4);
Value := StringReplace(Value, 'Usa', 'Etats-Unis');
Value := StringReplace(Value, 'Etats Unis', 'Etats-Unis');
Value := StringReplace(Value, 'Grande Bretagne', 'Grande-Bretagne');
Value := StringReplace(Value, 'Nouvelle Zélande', 'Nouvelle-Zélande');
// tri
memo := TStringList.Create;
memo.Text := StringReplace(Value, ' ', crlf);
SortList(memo);
Value := Trim(StringReplace(memo.Text, crlf, ' '));
memo.Free;
end;
SetField(fieldCountry, Value);
//********** image si demandée (rappel: ImportPicture = 0 si not CanSetPicture)
if (ImportPicture = 1) or (ImportPicture = 3) then
begin
Value := TextBetween(Value2, '
'' then GetPicture(Value);
end;
end;
//------------------------------------------------------------------------------
// extraction de l'année dans une chaine (texte_à_garder (année) )
//------------------------------------------------------------------------------
procedure ExtrAnnee(var str: string);
var
i: integer;
begin
i := LastPos('(1', str); // (1xxx ou (2xxx ça devrait suffire !!!
if i = 0 then
i := LastPos('(2', str);
if i > 0 then // année trouvée
begin
if annee = '' then
annee := Copy(str, i+1, 4);
str := Left(str, i -1); // chaine initiale sans l'année
end;
end;
//------------------------------------------------------------------------------
// formatage du nom du film
//------------------------------------------------------------------------------
function FormatMovieName2(str: string) :string;
var
i, j: integer;
begin
// une petite édition avant de formater
str := StringReplace(str, ' & ', ' et ');
str := StringReplace(str, ' & ', ' et ');
// MrCinéma traite bizarrement SES titres s'ils contiennent une virgule ou deux points
// exemple "2001 l'odyssée de l'espace" connu sous "2001 : l'odyssée de l'espace"
// il faut rentrer soit "2001" , soit "l'odyssee de l'espace"
// mais pas les 2 (il ne rend rien dans ce cas: oui, c'est bien bizarre...)
// donc on s'arrête aussi au premier de ces caractères (mais ça règle pas tout)
i := Pos(',', str);
j := Pos(':', str);
if (i <> 0) or (j <> 0) then // au moins 1 de trouvé
begin
if i = 0 then
i := j
else
begin
if (j <> 0) and (i > j) then i := j;
end;
str := Left(str, i -1);
end;
result := FormatMovieName(str);
end;
//------------------------------------------------------------------------------
// formatage d'une table (générique)
//------------------------------------------------------------------------------
function FormatTable(str1, flag: string) :string;
var
sepcel: string;
begin
// structure table
// = début de ligne
// texte | = 1 cellule
// .................... autres cellules
//
= fin de ligne
str1 := StringReplace(str1, crlf, ''); // supprimer les crlf
str1 := StringReplace(str1, '', sepchar2); // cellule du 'milieu'
str1 := StringReplace(str1, 'texte
// crlf+sepchar1+sepchar2 = |
| texte
// et le remplacer par crlf (à priori seuls cas possibles)
sepcel := crlf+sepchar1+sepchar2;
if Pos(sepcel, str1) <> 1 then sepcel := crlf+sepchar1;
str1 := StringReplace(str1, sepcel, crlf);
// s'il reste des crlf+sepchar2+sepchar2 ou crlf+sepchar2, il s'agit de continuations de lignes
// recoller les lignes si demandé
if flag = 'nocont' then
sepcel := crlf // on recolle pas
else
sepcel := ' '; // 1 blanc pour ne pas coller au précédent
str1 := StringReplace(str1, crlf+sepchar2+sepchar2, sepcel);
str1 := StringReplace(str1, crlf+sepchar2, sepcel);
//
str1 := StringReplace(str1, sepchar2+sepchar2, sepchar2); // supprimer les cellules vides
str1 := StringReplace(str1, sepchar2+sepchar2, sepchar2); // oui, c'est voulu
str1 := StringReplace(str1, sepchar2, ' '+sepchar2+' '); // decoller les séparateurs du texte
str1 := StringReplace(str1, sepchar1, ''); // et celui qui reste
result := str1; // suite du formatage dans FormatText
end;
//------------------------------------------------------------------------------
// extraction des infos des tables MrCinéma
//------------------------------------------------------------------------------
Function ExtractInfo(str1, from: string) :string;
var
i: integer;
begin
// si pas de séparateur de champs (sepchar2), alors on prend le mot suivant (anciennes définitions)
// d'où la recherche sur des mots 'incomplets' (et en plus, ça permet de couvrir plus de cas...)
// rappel: le mot cherché (from) peut contenir des majuscules
result := '';
i := Pos(AnsiLowerCase(from), AnsiLowerCase(str1));
if i = 0 then exit; // from non trouvé
str1 := Copy(str1, i + Length(from), Length(str1));
i := Pos(crlf, str1);
if i > 0 then // si pas de crlf, prendre tout
str1 := Left(str1, i-1);
i := Pos(sepchar2, str1);
if i = 0 then i := Pos(' ', str1);
result := Copy(str1, i +1, length(str1));
end;
//------------------------------------------------------------------------------
// récupération des identifiants 'sous-pages'
// GetSubParms(page)
//------------------------------------------------------------------------------
procedure GetSubParms(s: string);
var
Value: string;
i: integer;
begin
// infos utiles
// 5.2 les url ont la bougeotte donc ne pas pré-déterminer l'ordre
Value := TextBetween(s, 'L''essentiel', '');
if Pos('doPostBack', Value) > 0 then
begin
// formulaire et PostPage (ancienne méthode)
// à garder tant que la fonction doPostBack est définie dans la page (on ne sait jamais...)
// récupère le paramètre VIEWSTATE (ident de session)
viewstate := TextBetween(s, 'name="__VIEWSTATE"', '/>');
viewstate := TextBetween(viewstate, 'value="', '"');
// c'est un peu trop cablé: ordre et __EVENTARGUMENT='': serait mieux si c'était plus précis
// page histoire
idhistoire := TextBetween(Value, '__doPostBack(''', '''');
Value := RemainingText;
if idhistoire <> '' then
begin
idhistoire := StringReplace(idhistoire, '$', ':');
idhistoire := '__EVENTTARGET='+ idhistoire + '&__EVENTARGUMENT=&__VIEWSTATE=' + viewstate;
end;
// page avis de la rédaction
idavis := TextBetween(Value, '__doPostBack(''', '''');
Value := RemainingText;
if idavis <> '' then
begin
idavis := StringReplace(idavis, '$', ':');
idavis := '__EVENTTARGET='+ idavis + '&__EVENTARGUMENT=&__VIEWSTATE=' + viewstate;
end;
// page générique
idgenerique := TextBetween(Value, '__doPostBack(''', '''');
Value := RemainingText;
if idgenerique <> '' then
begin
idgenerique := StringReplace(idgenerique, '$', ':');
idgenerique := '__EVENTTARGET='+ idgenerique + '&__EVENTARGUMENT=&__VIEWSTATE=' + viewstate;
end;
// page anecdote
idanecdote := TextBetween(Value, '__doPostBack(''', '''');
if idanecdote <> '' then
begin
idanecdote := StringReplace(idanecdote, '$', ':');
idanecdote := '__EVENTTARGET='+ idanecdote + '&__EVENTARGUMENT=&__VIEWSTATE=' + viewstate;
end;
end
else
begin
// url normale (méthode actuelle)
// page histoire
idhistoire := GetUrlPage(Value, '>L''histoire');
// page avis de la rédaction
idavis := GetUrlPage(Value,'>L''avis de la rédaction');
// page générique
idgenerique := GetUrlPage(Value,'>Le générique complet');
// page anecdote
idanecdote := GetUrlPage(Value,'>L''anecdote');
end;
// si certains champs ne doivent pas être valorisés, inutile de lire les pages supplémentaires
if not CanSetField(fieldDescription) then idhistoire := '';
if not CanSetField(fieldComments) then idanecdote := '';
if not CanSetField(fieldComments) and (not CanSetField(fieldRating)) then idavis := '';
// pour générique complet
// il faut tester 'not' pour acteurs et réalisateur et producteur et durée et année
Value := '';
if CanSetField(fieldActors) then Value := 'ok';
if CanSetField(fieldDirector) then Value := 'ok';
if CanSetField(fieldProducer) then Value := 'ok';
if CanSetField(fieldLength) then Value := 'ok';
if CanSetField(fieldYear) then Value := 'ok';
if Value = '' then idgenerique := '';
end;
//------------------------------------------------------------------------------
// récupération de l'url d'une sous-page
// url := GetUrlPage(texte_contenant_l'url, texte_à_chercher)
//------------------------------------------------------------------------------
function GetUrlPage(wholetext, str: string) : string;
var
id: string;
i: integer;
begin
// l'url est avant le texte cherché
i := Pos(str, wholetext);
id := left(wholetext, i + length(str));
// et après le dernier '', '');
end;
//------------------------------------------------------------------------------
// traitement mode batch
//------------------------------------------------------------------------------
procedure MrCinemaBatch;
begin
SetField(fieldChecked, ''); // init film en traitement
case BatchMode of
1:
begin
// recherche par url
MovieName := GetField(fieldUrl); // pas d'url ou autre site, ignorer
if (MovieName <> '') and (Pos(MrCinemaUrlFilm, MovieName) > 0) then
AnalyzeMoviePageMrCinema(MovieName)
else
LogMessage('MrCinéma: non traitée url="'+Moviename+'"');
end;
2:
begin
// recherche par nom + réalisateur
MovieName := GetMovieName;
if MovieName <> '' then
begin
initBatchLook; // init paramètres de recherche
AnalyzePageMrCinema;
end else
LogMessage('MrCinéma: non traitée (pas de nom de film)');
end;
end; {case}
if filmok then
begin
SetField(fieldChecked, 'x'); // film ok
if ((ImportPicture = 2) or (ImportPicture = 3)) then
begin
// ok pour MrCinéma: rechercher l'affiche Cinéfil
// (forcément par nom + réalisateur tant qu'il n'y a pas de 2ème champ url)
MovieName := GetMovieName; // relecture
if MovieName <> '' then
begin
initBatchLook;
AnalyzePageCinefil;
end;
end; {import picture}
end; {filmok}
end;
//------------------------------------------------------------------------------
// traitement mode normal
//------------------------------------------------------------------------------
procedure MrCinemaNorm;
var
mname: string; // Input ne peut pas accéder aux variables déclarées dans les units
begin
// Monsieur cinéma
mname := GetMovieName;
msgano := 'Entrez le titre du film';
repeat
if not Input('MonsieurCinéma.com Import', msgano, mname) or (mname = '') then exit;
MovieName := mname;
AnalyzePageMrCinema;
until filmok;
// Cinéfil (si image demandée)
if (ImportPicture = 2) or (ImportPicture = 3) then
begin
MovieName := GetMovieName; // relecture
filmok := False;
msgano := 'Entrez le titre du film';
repeat
AnalyzePageCinefil;
if not filmok then
begin // page non trouvée ou erreur: on y retourne
mname := MovieName;
if not Input('Cinéfil.com Import', msgano, mname) or (mname = '') then
exit; // non saisie: on sort
MovieName := mname;
end;
until filmok;
end; {import picture}
end;
//------------------------------------------------------------------------------
// c'est ici que ça commence
//------------------------------------------------------------------------------
begin
if abort = 'o' then exit; // mode batch non confirmé
if firstcall <> 'done' then
begin // 1er appel: init paramètres
firstcall := 'done';
if not CheckVersion(3,5,0) then
begin
ShowMessage('Ce script requiert une version plus récente de Ant Movie Catalog (au moins la version 3.5.0)');
abort := 'o';
exit;
end;
calledBy := mrcinema_id; // identifiant appelant
batchlogfic := 'c:\amc_MrCinema_batchlog.txt'; // log pour mode batch
debug := False; // mode debug on/off
debugrep := 'd:\temp\'; // répertoire de stockage des fichiers
// récupère les variables user (utilisées plus d'une fois)
BatchMode := GetOption('Mode');
FormatTitre := GetOption('FormatTitre');
ImportPicture := GetOption('Image');
if not CanSetPicture then
ImportPicture := 0; // champ image non modifiable: inutile de lire
//
if BatchMode > 0 then // mode batch: confirmer le choix
begin
initBatchLog; // init log
if not ShowWarning(confbatch.Text) then
begin
AddToLog('mode batch annulé');
abort := 'o';
exit;
end;
end;
end;
// c'est parti
filmok := False;
if BatchMode = 0 then
MrCinemaNorm
else
MrCinemaBatch;
end.
|